# 浜鸿劯璇嗗埆鍔熻兘宸叉敞閲婏紝浜戜晶涓嶅啀杩涜浜鸿劯璇嗗埆
# 姝ゆ枃浠跺寘鍚汉鑴歌瘑鍒浉鍏崇殑鏈嶅姟锛屽凡鍏ㄩ儴娉ㄩ噴
# 浜鸿劯璇嗗埆鍔熻兘宸叉敼涓虹渚у鐞哱n
# import numpy as np
# from typing import List, Tuple, Optional, Dict, Any
# import base64
# import pickle
# from PIL import Image
# import io
# import os
# import time
# import requests
# from db.models.face_embedding import FaceEmbedding
# from sqlalchemy.orm import Session
# from sqlalchemy import text
# import logging
# from insightface.app import FaceAnalysis
# from config.settings import config
# from utils.logger import (
#     emobot_logger,
#     log_function_call,
#     log_function_result,
#     log_function_error,
# )
#
# logger = logging.getLogger(__name__)
#
#
# class FaceRecognitionService:
#     def __init__(self):
#         # Initialize face analysis model
#         start_time = time.time()
#         log_function_call("FaceRecognitionService.__init__")
#
#         try:
#             logger.info("Initializing FaceRecognitionService with buffalo_l model")
#
#             # Set INSIGHTFACE_HOME environment variable from config
#             if config.INSIGHTFACE_HOME:
#                 os.environ["INSIGHTFACE_HOME"] = config.INSIGHTFACE_HOME
#                 logger.info(f"Set INSIGHTFACE_HOME to: {config.INSIGHTFACE_HOME}")
#
#             self.face_analyzer = FaceAnalysis(root="models", name="buffalo_l")
#             self.face_analyzer.prepare(ctx_id=0, det_size=(640, 640))
#
#             duration = (time.time() - start_time) * 1000
#             logger.info(
#                 f"FaceRecognitionService initialized successfully in {duration:.2f}ms"
#             )
#             log_function_result("FaceRecognitionService.__init__", "success", duration)
#         except Exception as e:
#             duration = (time.time() - start_time) * 1000
#             log_function_error("FaceRecognitionService.__init__", e)
#             logger.error(f"Failed to initialize FaceRecognitionService: {e}")
#             raise
#
#     def download_image_from_url(self, image_url: str) -> Optional[np.ndarray]:
#         """Download image from URL and return as numpy array"""
#         try:
#             response = requests.get(image_url, timeout=10)
#             response.raise_for_status()
#
#             # Convert to PIL Image
#             image = Image.open(io.BytesIO(response.content))
#
#             # Convert to RGB if necessary
#             if image.mode != "RGB":
#                 image = image.convert("RGB")
#
#             # Convert to numpy array
#             return np.array(image)
#         except Exception as e:
#             logger.error(f"Failed to download image from {image_url}: {e}")
#             return None
#
#     def get_face_embedding_from_url(self, image_url: str) -> Optional[np.ndarray]:
#         """Get face embedding from image URL"""
#         try:
#             # Download image from URL
#             image_array = self.download_image_from_url(image_url)
#             if image_array is None:
#                 return None
#
#             # Convert RGB to BGR if needed (FaceAnalysis expects BGR)
#             if len(image_array.shape) == 3 and image_array.shape[2] == 3:
#                 image_array = image_array[:, :, ::-1]
#
#             # Detect faces
#             faces = self.detect_faces(image_array)
#             if not faces:
#                 return None
#
#             # Get face embedding from the largest face
#             face_objects = self.face_analyzer.get(image_array, faces)
#             if not face_objects:
#                 return None
#
#             return self.get_largest_face_embedding(face_objects)
#         except Exception as e:
#             logger.error(f"Failed to get face embedding from URL {image_url}: {e}")
#             return None
#
#     def detect_faces(self, image: np.ndarray) -> List[Tuple[int, int, int, int]]:
#         """Detect faces in image and return bounding boxes"""
#         start_time = time.time()
#         log_function_call(
#             "detect_faces",
#             {"image_shape": image.shape if hasattr(image, "shape") else "unknown"},
#         )
#
#         try:
#             logger.info("Starting face detection")
#             faces = self.face_analyzer.get(image)
#             result = [
#                 (
#                     int(face.bbox[0]),
#                     int(face.bbox[1]),
#                     int(face.bbox[2] - face.bbox[0]),
#                     int(face.bbox[3] - face.bbox[1]),
#                 )
#                 for face in faces
#             ]
#
#             duration = (time.time() - start_time) * 1000
#             logger.info(
#                 f"Face detection completed: {len(result)} faces detected in {duration:.2f}ms"
#             )
#             emobot_logger.log_face_operation("detection_success", None, None, None)
#             log_function_result("detect_faces", result, duration)
#
#             return result
#         except Exception as e:
#             duration = (time.time() - start_time) * 1000
#             logger.error(f"Face detection error: {e}")
#             emobot_logger.log_face_operation("detection_error", None, None, str(e))
#             log_function_error(
#                 "detect_faces",
#                 e,
#                 {"image_shape": image.shape if hasattr(image, "shape") else "unknown"},
#             )
#             return []
#
#     def save_face_embedding(
#         self,
#         db: Session,
#         user_id: str,
#         face_embedding: np.ndarray,
#         face_url: str,
#         face_image_path: str,
#         confidence_score: float = 0.0,
#     ) -> bool:
#         """Save face embedding to database"""
#         start_time = time.time()
#         log_function_call(
#             "save_face_embedding",
#             {
#                 "user_id": user_id,
#                 "embedding_dimension": len(face_embedding),
#                 "confidence_score": confidence_score,
#             },
#         )
#
#         try:
#             logger.info(f"Saving face embedding for user {user_id}")
#             emobot_logger.log_face_operation(
#                 "embedding_save_start", user_id, confidence_score
#             )
#
#             # Convert numpy array to binary
#             embedding_bytes = pickle.dumps(face_embedding)
#
#             face_embedding_record = FaceEmbedding(
#                 user_id=user_id,
#                 face_embedding=embedding_bytes,
#                 face_url=face_url,
#                 face_image_path=face_image_path,
#                 embedding_dimension=len(face_embedding),
#                 confidence_score=confidence_score,
#             )
#
#             db.add(face_embedding_record)
#             db.commit()
#
#             duration = (time.time() - start_time) * 1000
#             logger.info(
#                 f"Face embedding saved successfully for user {user_id} in {duration:.2f}ms"
#             )
#             emobot_logger.log_face_operation(
#                 "embedding_save_success", user_id, confidence_score
#             )
#             emobot_logger.log_db_operation(
#                 "create",
#                 "face_embedding",
#                 {"user_id": user_id, "embedding_dimension": len(face_embedding)},
#                 duration,
#             )
#             log_function_result("save_face_embedding", True, duration)
#
#             return True
#         except Exception as e:
#             duration = (time.time() - start_time) * 1000
#             logger.error(f"Save face embedding error: {e}")
#             emobot_logger.log_face_operation(
#                 "embedding_save_error", user_id, None, str(e)
#             )
#             emobot_logger.log_db_operation(
#                 "create_error",
#                 "face_embedding",
#                 {"user_id": user_id, "embedding_dimension": len(face_embedding)},
#                 duration,
#                 str(e),
#             )
#             db.rollback()
#             log_function_error(
#                 "save_face_embedding",
#                 e,
#                 {
#                     "user_id": user_id,
#                     "embedding_dimension": len(face_embedding),
#                     "confidence_score": confidence_score,
#                 },
#             )
#             return False
#
#     def find_matching_user(
#         self, db: Session, face_embedding: np.ndarray, threshold: float = 0.7
#     ) -> Optional[str]:
#         """Find matching user by face embedding"""
#         start_time = time.time()
#         log_function_call(
#             "find_matching_user",
#             {"embedding_dimension": len(face_embedding), "threshold": threshold},
#         )
#
#         try:
#             logger.info(f"Starting face matching with threshold {threshold}")
#             emobot_logger.log_face_operation("matching_start")
#
#             # Get all face embeddings from database
#             face_records = db.query(FaceEmbedding).all()
#             logger.info(f"Retrieved {len(face_records)} face records for matching")
#
#             best_match = None
#             best_similarity = 0
#
#             for record in face_records:
#                 # Deserialize embedding from database
#                 stored_embedding = pickle.loads(record.face_embedding)
#
#                 # Calculate cosine similarity
#                 similarity = self._calculate_cosine_similarity(
#                     face_embedding, stored_embedding
#                 )
#                 # Convert numpy float32 to native Python float for JSON serialization
#                 similarity = float(similarity)
#
#                 if similarity > best_similarity and similarity > threshold:
#                     best_similarity = similarity
#                     best_match = record.user_id
#
#             duration = (time.time() - start_time) * 1000
#             if best_match:
#                 logger.info(
#                     f"Found matching user {best_match} with similarity {best_similarity:.4f}"
#                 )
#                 emobot_logger.log_face_operation(
#                     "matching_success", best_match, best_similarity
#                 )
#             else:
#                 logger.info(
#                     f"No matching user found (best similarity: {best_similarity:.4f})"
#                 )
#                 emobot_logger.log_face_operation("matching_no_match")
#
#             emobot_logger.log_db_operation(
#                 "query",
#                 "face_embedding",
#                 {
#                     "records_count": len(face_records),
#                     "best_similarity": best_similarity,
#                     "match_found": best_match is not None,
#                 },
#                 duration,
#             )
#             log_function_result("find_matching_user", best_match, duration)
#
#             return best_match
#         except Exception as e:
#             duration = (time.time() - start_time) * 1000
#             logger.error(f"Face matching error: {e}")
#             emobot_logger.log_face_operation("matching_error", None, None, str(e))
#             log_function_error(
#                 "find_matching_user",
#                 e,
#                 {"embedding_dimension": len(face_embedding), "threshold": threshold},
#             )
#             return None
#
#     def _calculate_cosine_similarity(
#         self, embedding1: np.ndarray, embedding2: np.ndarray
#     ) -> float:
#         """Calculate cosine similarity between two embeddings"""
#         try:
#             dot_product = np.dot(embedding1, embedding2)
#             norm1 = np.linalg.norm(embedding1)
#             norm2 = np.linalg.norm(embedding2)
#
#             if norm1 == 0 or norm2 == 0:
#                 return 0.0
#
#             result = dot_product / (norm1 * norm2)
#             # Convert numpy float32 to native Python float for JSON serialization
#             return float(result)
#         except Exception as e:
#             logger.error(f"Similarity calculation error: {e}")
#             return 0.0
#
#     def process_image_for_face_recognition(
#         self, db: Session, image_source: str
#     ) -> Optional[Dict[str, Any]]:
#         """Process image for face recognition and return user info if found"""
#         start_time = time.time()
#         log_function_call(
#             "process_image_for_face_recognition", {"image_source": image_source}
#         )
#
#         try:
#             logger.info(f"Processing image for face recognition: {image_source}")
#             emobot_logger.log_face_operation("processing_start")
#
#             # Check if image_source is a URL or local path
#             if image_source.startswith(("http://", "https://")):
#                 # Download image from URL
#                 image_array = self.download_image_from_url(image_source)
#                 if image_array is None:
#                     logger.error("Failed to download image from URL")
#                     return None
#             else:
#                 # Load image from local path
#                 image = Image.open(image_source)
#                 image_array = np.array(image)
#
#             logger.info(f"Image loaded successfully: {image_array.shape}")
#
#             # Convert RGB to BGR if needed (FaceAnalysis expects BGR)
#             if len(image_array.shape) == 3 and image_array.shape[2] == 3:
#                 image_array = image_array[:, :, ::-1]
#                 logger.info("Converted image from RGB to BGR")
#
#             # Get faces from FaceAnalysis
#             face_objects = self.face_analyzer.get(image_array)
#             if not face_objects:
#                 logger.error("Could not generate face embedding")
#                 logger.error(f"image local path: {image_source}")
#                 emobot_logger.log_face_operation("embedding_generation_failed")
#                 return None
#
#             # Use the largest face
#             face_embedding = self.get_largest_face_embedding(face_objects)
#             if face_embedding is None:
#                 logger.error("Could not generate face embedding")
#                 emobot_logger.log_face_operation("embedding_generation_failed")
#                 return None
#
#             # Find matching user
#             matched_user_id = self.find_matching_user(db, face_embedding)
#
#             if matched_user_id:
#                 logger.info(f"Found existing user {matched_user_id}")
#                 result = {
#                     "user_id": matched_user_id,
#                     "face_detected": True,
#                     "confidence": 0.8,  # Placeholder confidence
#                 }
#                 emobot_logger.log_face_operation(
#                     "existing_user_matched", matched_user_id, 0.8
#                 )
#             else:
#                 # Create new user and save face embedding
#                 logger.info("No matching user found, creating new user")
#                 import uuid
#
#                 new_user_id = str(uuid.uuid4())
#
#                 # Save face embedding for new user
#                 success = self.save_face_embedding(
#                     db=db,
#                     user_id=new_user_id,
#                     face_embedding=face_embedding,
#                     face_url=image_source,
#                     face_image_path=image_source,
#                     confidence_score=0.8,
#                 )
#
#                 if success:
#                     logger.info(f"Created new user {new_user_id} with face embedding")
#                     result = {
#                         "user_id": new_user_id,
#                         "face_detected": True,
#                         "confidence": 0.8,
#                         "new_user_created": True,
#                     }
#                     emobot_logger.log_face_operation(
#                         "new_user_created", new_user_id, 0.8
#                     )
#                 else:
#                     logger.error("Failed to save face embedding for new user")
#                     result = {
#                         "user_id": None,
#                         "face_detected": True,
#                         "confidence": 0.0,
#                         "face_box": [
#                             int(x) for x in faces[0]
#                         ],  # Convert numpy int32 to native Python int
#                     }
#                     emobot_logger.log_face_operation("new_user_creation_failed")
#
#             duration = (time.time() - start_time) * 1000
#             logger.info(f"Face recognition processing completed in {duration:.2f}ms")
#             log_function_result("process_image_for_face_recognition", result, duration)
#
#             return result
#
#         except Exception as e:
#             duration = (time.time() - start_time) * 1000
#             logger.error(f"Face recognition processing error: {e}")
#             emobot_logger.log_face_operation("processing_error", None, None, str(e))
#             log_function_error(
#                 "process_image_for_face_recognition", e, {"image_path": image_path}
#             )
#             return None
#
#     # 选出面积最大的脸（即 bounding box 最大的）
#     def get_largest_face_embedding(self, faces):
#         def face_area(face):
#             x1, y1, x2, y2 = face.bbox
#             return (x2 - x1) * (y2 - y1)
#
#         largest_face = max(faces, key=face_area)
#         return largest_face.embedding
#